﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using InkFx.WinControl.Core;
using InkFx.WinControl.Utils;
using DA = InkFx.WinControl.XIDEAlignment;
using DTG = InkFx.WinControl.XIDETabGroup;
using DTGS = InkFx.WinControl.XIDETabGroupState;
using DTGP = InkFx.WinControl.XIDETabGroupPage;

namespace InkFx.WinControl
{
    [ToolboxItem(true)]
    public class XIDEPanel : System.Windows.Forms.UserControl
    {
        public XIDEPanel()
        {
            SetStyle(Win32API.ControlStylesUAORSD, true); 
            base.BackColor = Color.Transparent;
            base.DoubleBuffered = true;
            
            if (!DesignMode)
            {
                m_CenterPanel = new XIDEPanelCenter(this);
                m_CenterPanel.Parent = this;
                m_MenuStrip = new ContextMenuStrip();
                m_MenuStrip.ItemClicked += MenuStrip_ItemClicked;
                this.DoLayout();
            }
        }



        protected XIDETabGroup m_ActiveTabGroup = null;
        protected XIDEPanelCenter m_CenterPanel = null;
        protected ContextMenuStrip m_MenuStrip = null;
        protected List<XIDETabGroup> m_ListTabGroup = new List<XIDETabGroup>();
        public XIDEPanelCenter CenterPanel
        {
            get { return m_CenterPanel; }
        }
        public Rectangle RectIDEInner
        {
            get
            {
                var size = this.Size;
                var padding = this.Padding;
                return new Rectangle(padding.Left, padding.Top, size.Width - padding.Left - padding.Right, size.Height - padding.Top - padding.Bottom);
            }
        }
        public XIDETabGroup ActiveTabGroup
        {
            get { return m_ActiveTabGroup; }
            set
            {
                var oldActiveGroup = m_ActiveTabGroup;
                m_ActiveTabGroup = value;
                if (oldActiveGroup != null) { oldActiveGroup.ResetRect(); oldActiveGroup.Invalidate(); }
                if (m_ActiveTabGroup != null) { m_ActiveTabGroup.ResetRect(); m_ActiveTabGroup.Invalidate(); }
                if (m_ActiveTabGroup != null && !m_ActiveTabGroup.ContainsFocus) { m_ActiveTabGroup.Focus(); }
            }
        }



        public XIDETabGroup FindTabGroup(XIDEFrame ctrl)
        {
            var listGroup = this.GetListTabGroup();
            foreach (var group in listGroup)
                foreach (var page in group.ListPage)
                    if (page.Control == ctrl) return group;

            return null;
        }
        public XIDETabGroup FindTabGroup(XIDETabGroupPage page)
        {
            var listGroup = this.GetListTabGroup();
            foreach (var group in listGroup) 
                foreach (var page2 in group.ListPage)
                    if (page2 == page) return group;

            return null;
        }
        public XIDETabGroup FindTabGroup(InkFx.WinControl.SplitterPanel panel)
        {
            var listGroup = this.GetListTabGroup();
            var group = listGroup.Find(x => x.ParentSplitPanel == panel);
            return group;
        }
        public System.Windows.Forms.Control FindTabGroupOrSplitControl(InkFx.WinControl.SplitterPanel panel, out bool hide)
        {
            hide = false;
            var ctrls = panel.Controls;
            if (ctrls != null && ctrls.Count >= 1)
                foreach (System.Windows.Forms.Control ctrl in ctrls)
                {
                    if (ctrl.Disposing || ctrl.IsDisposed) { continue; }
                    if (ctrl is XIDEPanelCenter) { hide = false; return ctrl; }
                    if (ctrl is XIDESplitControl) { hide = ((XIDESplitControl)ctrl).PanelAllCollapsed; return ctrl; }
                    if (ctrl is XIDETabGroup) { hide = ((XIDETabGroup)ctrl).State != DTGS.Expand; if (!hide) { ctrl.Visible = true; } return ctrl; }
                }

            hide = true;
            var group = FindTabGroup(panel);
            if (group != null) return group;
            return null;
        }

        public void RegTabGroup(XIDETabGroup group)
        {
            if (group == null || group.IDEPanel != this || group.Disposing || group.IsDisposed) return;
            this.m_ListTabGroup.Add(group);
        }
        public List<XIDETabGroup> GetListTabGroup()
        {
            m_ListTabGroup.RemoveAll(x => x.IDEPanel != this || x.Disposing || x.IsDisposed);
            return m_ListTabGroup;
        }
        public List<XIDEFrame> GetListTabFrame()
        {
            List<XIDETabGroup> listGroup = GetListTabGroup();
            if (listGroup == null) return null;

            var listFrame = new List<XIDEFrame>();
            foreach (var group in listGroup)
                foreach (var page in group.ListPage)
                    if (page.Control != null && !page.Control.Disposing && !page.Control.IsDisposed)
                        listFrame.Add(page.Control);

            return listFrame;
        } 

        public XIDETabGroup DoDock(XIDEFrame ctrl, DA align)
        {
            return DoDock(ctrl, align, DTGS.Expand);
        }
        public XIDETabGroup DoDock(XIDEFrame ctrl, DA align, DTGS state)
        {
            RemoveTabPage(ctrl);
            XIDETabGroup group = new XIDETabGroup(this, null, align);
            ctrl.Dock = DockStyle.Fill;
            group.AppendTabPage(ctrl);

            if (state == DTGS.Float)
            {
                XIDEFloatForm.ShowControl(this, group, Rectangle.Empty);
            }
            else
            {
                var group2 = DoDock(group, align);
                if (group2 != null)
                {
                    group2.Alignment = align;
                    group2.State = state;
                }
                return group2;
            }
            return group;
        }
        public XIDETabGroup DoDock(XIDETabGroup group, DA align)
        {
            if (group == null) return null;
            group.ReleaseParent();

            var ctrls = this.Controls;
            System.Windows.Forms.Control ctrl1 = null;
            foreach (var c in ctrls) { if ((c is XIDESplitControl) || (c is XIDETabGroup) || (c is XIDEPanelCenter)) { ctrl1 = (System.Windows.Forms.Control)c; break; } }
            if (ctrl1 == null) return null;

            if (align == DA.Center)
            {
                #region  附着到 中央面板

                var centerGroup = m_CenterPanel.FindGroup();
                if (centerGroup != null)
                {
                    return centerGroup.DoDock(group, DA.Center);
                }
                else
                {
                    group.DisposeFloatForm();
                    group.Alignment = align;
                    group.State = DTGS.Expand;
                    group.Parent = m_CenterPanel;
                    group.Focus();
                    return group;
                }

                #endregion
            }
            else
            {
                #region  执行拆分

                this.SuspendLayout();
                group.DisposeFloatForm();
                group.Alignment = align;
                System.Windows.Forms.Control ctrl0 = group;

                var parent = ctrl1.Parent;
                var splitCtrl = new XIDESplitControl(this);
                splitCtrl.Dock = DockStyle.Fill;
                splitCtrl.Size = parent.Size;

                if (align == XIDEAlignment.Top || align == XIDEAlignment.Bottom)
                { splitCtrl.Orientation = Orientation.Horizontal; }
                if (align == XIDEAlignment.Right || align == XIDEAlignment.Bottom)
                { var temp = ctrl0; ctrl0 = ctrl1; ctrl1 = temp; }

                ctrl1.Parent = null;
                splitCtrl.Size = parent.Size;
                splitCtrl.Parent = parent;
                ctrl0.Parent = splitCtrl.Panel1;
                ctrl1.Parent = splitCtrl.Panel2;

                //if (ctrl0 is IDETabGroup) { ((IDETabGroup)ctrl0).Parent = splitCtrl.Panel1; }
                //if (ctrl0 is IDESplitControl) { ((IDESplitControl)ctrl0).Parent = splitCtrl.Panel1; }
                //else { ctrl0.Parent = splitCtrl.Panel1; }

                //if (ctrl1 is IDETabGroup) { ((IDETabGroup)ctrl1).Parent = splitCtrl.Panel2; }
                //if (ctrl1 is IDESplitControl) { ((IDESplitControl)ctrl1).Parent = splitCtrl.Panel2; }
                //else { ctrl1.Parent = splitCtrl.Panel2; }

                group.State = DTGS.Expand;
                this.ResumeLayout();
                group.Focus();
                return group;

                #endregion
            }

        }
        public void DoDock(XIDETabGroup group, XIDEEventArgs e)
        {
            if (group == null || e == null) return;
            group.ReleaseParent();

            #region  在Group上拆分

            if (e.Control != null && e.TipLayout != null)
            {
                this.SuspendLayout();
                e.Control.DoDock(group, e.Alignment);
                this.ResumeLayout(true);
            }

            #endregion

            #region  四边区域扩展

            else if (e.TipArea != null)
            {
                this.SuspendLayout();
                this.DoDock(group, e.TipArea.Align);
                this.ResumeLayout(true);
            }

            #endregion
        }
        public void RemoveTabPage(XIDEFrame ctrl)
        {
            if (ctrl == null) return;
            var group = FindTabGroup(ctrl);
            if (group != null) { group.RemoveTabPage(ctrl); }
        }
        public void RemoveTabPage(XIDETabGroupPage page)
        {
            if (page == null) return;
            var group = FindTabGroup(page);
            if (group != null) { group.RemoveTabPage(page); }
        }
        public void RemoveTabGroup(XIDETabGroup group)
        {
            if (group == null) return;
            group.DoClose();
        }



        /// <summary>
        /// 判断 ctrl 的 子孙控件中, 是否包含 CenterPanel
        /// </summary>
        public bool ContainsCenterPanel(System.Windows.Forms.Control ctrl)
        {
            System.Windows.Forms.Control parent = this.CenterPanel;
            while (parent != null && !parent.Disposing && !parent.IsDisposed)
            {
                if (parent == ctrl) return true;
                parent = parent.Parent;
            }
            return false;
        }




        private const int DOCK_SIZE = 25;
        protected bool m_DoLayout = false;
        public void DoLayout()
        {
            if (m_DoLayout) return;

            try
            {
                m_DoLayout = true;
                //Console.WriteLine("IDEPanel.DoLayout() " + DateTime.Now.ToString("HH:mm:ss fff"));
                const int padding = XIDEFloatForm.PADDING;
                var listGroup = this.GetListTabGroup();
                bool top = listGroup.Find(x => x.Alignment == XIDEAlignment.Top && (x.State == DTGS.Collapse || x.State == DTGS.Popup)) != null;
                bool bottom = listGroup.Find(x => x.Alignment == XIDEAlignment.Bottom && (x.State == DTGS.Collapse || x.State == DTGS.Popup)) != null;
                bool left = listGroup.Find(x => x.Alignment == XIDEAlignment.Left && (x.State == DTGS.Collapse || x.State == DTGS.Popup)) != null;
                bool right = listGroup.Find(x => x.Alignment == XIDEAlignment.Right && (x.State == DTGS.Collapse || x.State == DTGS.Popup)) != null;

                this.Padding = new Padding((left ? DOCK_SIZE : padding), (top ? DOCK_SIZE : padding), (right ? DOCK_SIZE : padding), (bottom ? DOCK_SIZE : padding));
                //Console.WriteLine(this.Padding);
            }
            finally { m_DoLayout = false; }
        }


        #region  重 置 布 局

        public int LayoutSuspendCount { get; private set; }
        public bool IsLayoutSuspended { get { return LayoutSuspendCount >= 1; } }

        protected bool m_ResumeLayout = false;
        public virtual new bool SuspendLayout()
        {
            if (m_ResumeLayout) return false;

            LayoutSuspendCount++;
            base.SuspendLayout();
            return true;
        }
        public virtual new void ResumeLayout()
        {
            this.ResumeLayout(true);
        }
        public virtual new void ResumeLayout(bool performLayout)
        {
            if (m_ResumeLayout) return;
            try
            {
                m_ResumeLayout = true;
                LayoutSuspendCount--;

                if (LayoutSuspendCount <= 0)
                {
                    LayoutSuspendCount = 0;
                    ResetLayout();
                }

                base.ResumeLayout(performLayout);
                this.Invalidate();
            }
            finally { m_ResumeLayout = false; }
        }

        public void ResetLayout()
        {
            var ctrls = this.Controls;
            foreach (var ctrl in ctrls)
            {
                if (ctrl is XIDEPanelCenter) { ((XIDEPanelCenter)ctrl).ResetLayout(); }
                if (ctrl is XIDESplitControl) { ((XIDESplitControl)ctrl).ResetLayout(); }
            }
            this.DoLayout();
        }

        #endregion


        #region  弹 出 菜 单

        /// <summary>
        /// 执行 右键弹窗菜单, 不建议改写本函数: 建议改写 CreateTabMenuItems(*) 菜单选项函数 和 OoMenuStripClick(*) 菜单执行函数
        /// </summary>
        /// <param name="group">触发菜单的 Group</param>
        /// <param name="page">触发菜单的 Page</param>
        /// <param name="point">触发菜单时, 相对于 Group 的坐标</param>
        /// <param name="items">需要显示的菜单项</param>
        public virtual void OpenMenuStrip(XIDETabGroup group, XIDETabGroupPage page, Point point, List<XIDEMenuItem> items)
        {
            if (items == null || items.Count <= 0) return;
            if (m_MenuStrip == null || m_MenuStrip.Disposing || m_MenuStrip.IsDisposed) return;

            m_MenuStrip.Items.Clear();
            foreach (var item1 in items)
            {
                var item2 = new ToolStripMenuItem(item1.Text, item1.Icon);
                item2.Name = item1.Name;
                item2.Enabled = item1.Enabled;
                item2.Tag = new XIDEMenuItemInfo(group, page, item1);
                m_MenuStrip.Items.Add(item2);
            }

            m_MenuStrip.Show(group, point);
        }

        /// <summary>
        /// 通过指定的 TabGroup, 计算出 该TabGroup 即将显示的 右键菜单选项
        /// </summary>
        public virtual List<XIDEMenuItem> CreateTabMenuItems(XIDETabGroup group, XIDETabGroupPage page, bool isRightButton)
        {
            var items = new List<XIDEMenuItem>();

            if (group.Alignment == DA.Center && !isRightButton)
            {
                foreach (var page2 in group.ListPage)
                {
                    items.Add(new XIDEMenuItem("DoFocusPage", page2.Text, true, page2));
                }
            }
            else
            {
                items.Add(new XIDEMenuItem("DoFloat", "浮动", true));
                items.Add(new XIDEMenuItem("DoExpand", "停靠", true));
                items.Add(new XIDEMenuItem("DoCollapse", "折叠", true));
                items.Add(new XIDEMenuItem("DoHide", "隐藏", true));
            }
            return items;
        }

        /// <summary>
        /// 执行菜单选项的单击触发
        /// </summary>
        /// <param name="group">触发菜单的 Group</param>
        /// <param name="page">触发菜单的 Page</param>
        /// <param name="item">触发菜单的 菜单项</param>
        public virtual void OoMenuStripClick(XIDETabGroup group, XIDETabGroupPage page, XIDEMenuItem item)
        {
            if (item.Name == "DoFocusPage")
            {
                #region  右键菜单 选中溢出的 Page

                var page2 = item.Tag as XIDETabGroupPage;
                if (page2 != null)
                {
                    if (page2.RectRealTitle.Width <= 0) group.SetSelectedFirstPage(page2);
                    else group.SetSelectedPage(page2);
                }

                #endregion
            }
            else if (item.Name == "DoFloat")
            {
                #region  将选中的Group以窗体模式悬浮

                #endregion
            }
            else if (item.Name == "DoExpand")
            {
                #region  展开选中的Group

                #endregion
            }
            else if (item.Name == "DoCollapse")
            {
                #region  折叠选中的Group

                #endregion
            }
            else if (item.Name == "DoHide")
            {
                #region  隐藏选中的Group

                #endregion
            }
        }
        
        
        private void MenuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            var item1 = e.ClickedItem;
            var info = item1 == null ? null : item1.Tag as XIDEMenuItemInfo;
            if (info != null) OoMenuStripClick(info.Group, info.Page, info.Item);
        }

        #endregion


        #region  继 承 改 写

        public new void Invalidate()
        {
            //var size = this.Size;
            //var padding = this.Padding;
            //base.Invalidate(new Rectangle(0, 0, size.Width, padding.Top));
            //base.Invalidate(new Rectangle(0, size.Height - padding.Bottom, size.Width, padding.Bottom));
            //base.Invalidate(new Rectangle(0, 0, padding.Left, size.Height));
            //base.Invalidate(new Rectangle(size.Width - padding.Right, 0, size.Width, size.Height));
            this.Invalidate(false);
        }

        //protected override CreateParams CreateParams
        //{
        //    get
        //    {
        //        CreateParams cp = base.CreateParams;
        //        cp.ExStyle |= (int)WindowStyles.WS_CLIPCHILDREN;
        //        return cp;
        //    }
        //}
        protected override void WndProc(ref Message m)
        {
            //if (m.Msg == Win32Msg.WM_SIZE)
            //{
            //    Win32API.SetExStyle(this.Handle, WindowStyles.WS_CLIPCHILDREN);
            //    Task.SetDelay(this.Handle.ToInt32(), () => Invoke((ThreadStart)(() =>
            //    {
            //        Console.WriteLine("Run Delay");
            //        Win32API.DelExStyle(this.Handle, WindowStyles.WS_CLIPCHILDREN);
            //        //m_Set_WS_CLIPCHILDREN = false;
            //        //base.Invalidate();
            //        base.Refresh();
            //    })), 1000);
            //}

            base.WndProc(ref m);
        }

        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            //if (this.IsHandleCreated && !this.Disposing && !this.IsDisposed)
            //{
            //    //Win32API.DelExStyle(this.Handle, WindowStyles.WS_CLIPCHILDREN);
            //    //this.Invalidate();

            //    //Task.SetTimeout(() => Invoke((ThreadStart) (() =>
            //    //{
            //    //    Win32API.SetExStyle(this.Handle, WindowStyles.WS_CLIPCHILDREN);
            //    //    this.Invalidate();
            //    //})), 2000);
            //}
        }
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            this.Invalidate();
        }
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            this.Invalidate();
        }
        protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);
            this.Invalidate();
        }
        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);
            this.Invalidate();
        }
        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnClick(e);

            if (m_HashRectPage == null || m_HashRectPage.Count <= 0) return;
            Point point1 = System.Windows.Forms.Control.MousePosition;
            Point point2 = this.PointToClient(point1);

            Hashtable hash = null;
            lock (m_HashRectPage.SyncRoot) hash = (Hashtable)m_HashRectPage.Clone();

            foreach (var key in hash.Keys)
            {
                var value = hash[key];
                if (!(key is Rectangle) || !(value is XIDETabGroupPage)) continue;
                var rect = (Rectangle)key;
                var page = (XIDETabGroupPage)value;
                if (page.ParentGroup != null && !page.ParentGroup.Disposing && !page.ParentGroup.IsDisposed && rect.Contains(point2))
                {
                    XIDEPopPanel.TogglePopGroup(page);
                }
            }
        }


        protected override void OnPaint(PaintEventArgs e)
        {
            //if (m_DrawingSplitter) return;
            base.OnPaint(e);


            Graphics g = e.Graphics;

            var listGroup = this.GetListTabGroup();
            var listTop = listGroup.FindAll(x => x.Alignment == DA.Top && (x.State == DTGS.Collapse || x.State == DTGS.Popup));
            var listBottom = listGroup.FindAll(x => x.Alignment == DA.Bottom && (x.State == DTGS.Collapse || x.State == DTGS.Popup));
            var listLeft = listGroup.FindAll(x => x.Alignment == DA.Left && (x.State == DTGS.Collapse || x.State == DTGS.Popup));
            var listRight = listGroup.FindAll(x => x.Alignment == DA.Right && (x.State == DTGS.Collapse || x.State == DTGS.Popup));

            lock (m_HashRectPage.SyncRoot) m_HashRectPage.Clear();
            DrawRivetedTabGroup(g, XIDEAlignment.Top, listTop);
            DrawRivetedTabGroup(g, XIDEAlignment.Bottom, listBottom);
            DrawRivetedTabGroup(g, XIDEAlignment.Left, listLeft);
            DrawRivetedTabGroup(g, XIDEAlignment.Right, listRight);

            //if (this.IsSplitMoving)
            //{
            //    //RepaintSplitterRect();
            //    var handle = this.Handle; //Win32API.GetDesktopWindow();
            //    Win32API.DrawSplitHelper(handle, m_RectSplitter);
            //    //this.Invalidate(true);
            //    //this.Refresh();
            //}
        }

        #endregion





        private readonly Hashtable m_HashRectPage =  Hashtable.Synchronized(new Hashtable());
        protected virtual void DrawRivetedTabGroup(Graphics g, XIDEAlignment align, List<XIDETabGroup> listGroup)
        {
            if (g == null || align == XIDEAlignment.None || align == XIDEAlignment.Center) return;
            if (listGroup == null || listGroup.Count <= 0) return;

            var size = this.Size;
            var padding = this.Padding;
            var enable = this.Enabled;
            if (align == XIDEAlignment.Top)
            {
                #region  Top

                int x = padding.Left;
                int y = 0;
                for (int i = 0, len = listGroup.Count; i < len; i++)
                {
                    var group = listGroup[i];
                    foreach (var page in group.ListPage)
                    {
                        Size textSize = GraphicsHelper.GetStringPixel(g, page.Text, this.Font);
                        Rectangle rect = new Rectangle(x, y, 6 + 16 + 3 + textSize.Width, DOCK_SIZE - 3);
                        DrawRivetedTabPage(g, enable, group, page, rect, textSize);
                        x = x + rect.Width + 1;
                        lock (m_HashRectPage.SyncRoot) m_HashRectPage[rect] = page;
                    }
                }

                #endregion
            }
            else if (align == XIDEAlignment.Bottom)
            {
                #region Bottom

                int x = padding.Left;
                int y = size.Height - DOCK_SIZE + 3;
                for (int i = 0, len = listGroup.Count; i < len; i++)
                {
                    var group = listGroup[i];
                    foreach (var page in group.ListPage)
                    {
                        Size textSize = GraphicsHelper.GetStringPixel(g, page.Text, this.Font);
                        Rectangle rect = new Rectangle(x, y, 6 + 16 + 3 + textSize.Width, DOCK_SIZE - 3);
                        DrawRivetedTabPage(g, enable, group, page, rect, textSize);
                        x = x + rect.Width + 1;
                        lock (m_HashRectPage.SyncRoot) m_HashRectPage[rect] = page;
                    }
                }

                #endregion
            }
            else if (align == XIDEAlignment.Left)
            {
                #region Left

                int x = 0;
                int y = padding.Top;
                for (int i = 0, len = listGroup.Count; i < len; i++)
                {
                    var group = listGroup[i];
                    foreach (var page in group.ListPage)
                    {
                        Size textSize = GraphicsHelper.GetStringPixel(g, page.Text, this.Font);
                        Rectangle rect = new Rectangle(x, y, DOCK_SIZE - 3, 6 + 16 + 3 + textSize.Width);
                        DrawRivetedTabPage(g, enable, group, page, rect, textSize);
                        y = y + rect.Height + 1;
                        lock (m_HashRectPage.SyncRoot) m_HashRectPage[rect] = page;
                    }
                }

                #endregion
            }
            else if (align == XIDEAlignment.Right)
            {
                #region Right

                int x = size.Width - DOCK_SIZE + 3;
                int y = padding.Top;
                for (int i = 0, len = listGroup.Count; i < len; i++)
                {
                    var group = listGroup[i];
                    foreach (var page in group.ListPage)
                    {
                        Size textSize = GraphicsHelper.GetStringPixel(g, page.Text, this.Font);
                        Rectangle rect = new Rectangle(x, y, DOCK_SIZE - 3, 6 + 16 + 3 + textSize.Width);
                        DrawRivetedTabPage(g, enable, group, page, rect, textSize);
                        y = y + rect.Height + 1;
                        lock (m_HashRectPage.SyncRoot) m_HashRectPage[rect] = page;
                    }
                }

                #endregion
            }
        }


        private static Color m_TitleColor = Color.LightSteelBlue;
        private static Color m_FocusColor = Color.LightYellow;
        protected virtual void DrawRivetedTabPage(Graphics g, bool enable, DTG group, DTGP page, Rectangle rectPage, Size textSize)
        {
            Image icon = page.Icon;

            var align = group.Alignment;
            Rectangle rectIcon = Rectangle.Empty;
            Rectangle rectText = Rectangle.Empty;

            if (align == DA.Top) { rectIcon = icon == null ? new Rectangle(rectPage.X + 3, rectPage.Y + 3, 0, 0) : new Rectangle(rectPage.X + 3, rectPage.Y + 3, 16, 16); }
            else if (align == DA.Bottom) { rectIcon = icon == null ? new Rectangle(rectPage.X + 3, rectPage.Y + 3, 0, 0) : new Rectangle(rectPage.X + 3, rectPage.Y + 3, 16, 16); }
            else if (align == DA.Left) { rectIcon = icon == null ? new Rectangle(rectPage.X + 3, rectPage.Y + 3, 0, 0) : new Rectangle(rectPage.X + 3, rectPage.Y + 3, 16, 16); }
            else if (align == DA.Right) { rectIcon = icon == null ? new Rectangle(rectPage.X + 3, rectPage.Y + 3, 0, 0) : new Rectangle(rectPage.X + 3, rectPage.Y + 3, 16, 16); }

            if (align == DA.Top) { rectText = new Rectangle(rectIcon.Right + 3, rectPage.Y, textSize.Width, rectPage.Height); }
            else if (align == DA.Bottom) { rectText = new Rectangle(rectIcon.Right + 3, rectPage.Y, textSize.Width, rectPage.Height); }
            else if (align == DA.Left) { rectText = new Rectangle(rectPage.X, rectIcon.Bottom + 3, rectPage.Width, textSize.Width); }
            else if (align == DA.Right) { rectText = new Rectangle(rectPage.X, rectIcon.Bottom + 3, rectPage.Width, textSize.Width); }


            DrawRivetedTabPageBack(g, enable, group, page, rectPage);
            DrawRivetedTabPageText(g, enable, group, page, rectText);
            DrawRivetedTabPageIcon(g, enable, group, page, rectIcon, icon);
        }
        protected virtual void DrawRivetedTabPageBack(Graphics g, bool enable, DTG group, DTGP page, Rectangle rectPage)
        {
            Point ctrlPoint = Win32API.GetMouseCtrlPoint((System.Windows.Forms.Control)this);
            bool hover = rectPage.Contains(ctrlPoint);
            bool select = group.PopupPage == page;

            Rectangle rect = rectPage;
            var align = group.Alignment;
            RoundStyle doundStyle = RoundStyle.None;
            if (align == DA.Top) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); doundStyle = RoundStyle.Top; }
            else if (align == DA.Bottom) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); doundStyle = RoundStyle.Bottom; }
            else if (align == DA.Left) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); doundStyle = RoundStyle.Left; }
            else if (align == DA.Right) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height); doundStyle = RoundStyle.Right; }

            //选中的 Page 突出显示
            //if (select)
            //{
            //    if (align == DA.Top) { rect = new Rectangle(rect.X, rect.Y, rect.Width, rect.Height + 1); }
            //    else if (align == DA.Bottom) { rect = new Rectangle(rect.X, rect.Y - 1, rect.Width, rect.Height + 1); }
            //    else if (align == DA.Left) { rect = new Rectangle(rect.X, rect.Y, rect.Width + 1, rect.Height); }
            //    else if (align == DA.Right) { rect = new Rectangle(rect.X - 1, rect.Y, rect.Width + 1, rect.Height); }
            //}


            //Image headImg = null;
            //if (align == DA.Top) { headImg = !this.Enabled ? theme.TabControl_HeadTop_Disable : (isSelect ? theme.TabControl_HeadTop_Pressed : isHover ? theme.TabControl_HeadTop_Hover : theme.TabControl_HeadTop); }
            //else if (align == DA.Bottom) { headImg = !this.Enabled ? theme.TabControl_HeadBottom_Disable : (isSelect ? theme.TabControl_HeadBottom_Pressed : isHover ? theme.TabControl_HeadBottom_Hover : theme.TabControl_HeadBottom); }
            //else if (align == DA.Left) { headImg = !this.Enabled ? theme.TabControl_HeadLeft_Disable : (isSelect ? theme.TabControl_HeadLeft_Pressed : isHover ? theme.TabControl_HeadLeft_Hover : theme.TabControl_HeadLeft); }
            //else if (align == DA.Right) { headImg = !this.Enabled ? theme.TabControl_HeadRight_Disable : (isSelect ? theme.TabControl_HeadRight_Pressed : isHover ? theme.TabControl_HeadRight_Hover : theme.TabControl_HeadRight); }

            //if (headImg != null)
            //{
            //    if (align == DA.Top) { GraphicsHelper.DrawBorderImageAndFill(g, headImg, rect.X, rect.Y, rect.Width, rect.Height, 2, 0, 2, 2, FillStyle.RepeatXY); }
            //    else if (align == DA.Bottom) { GraphicsHelper.DrawBorderImageAndFill(g, headImg, rect.X, rect.Y, rect.Width, rect.Height, 0, 2, 2, 2, FillStyle.RepeatXY); }
            //    else if (align == DA.Left) { GraphicsHelper.DrawBorderImageAndFill(g, headImg, rect.X, rect.Y, rect.Width, rect.Height, 2, 2, 2, 0, FillStyle.RepeatXY); }
            //    else if (align == DA.Right) { GraphicsHelper.DrawBorderImageAndFill(g, headImg, rect.X, rect.Y, rect.Width, rect.Height, 2, 2, 0, 2, FillStyle.RepeatXY); }
            //}

            bool press = MouseButtons == MouseButtons.Left;
            Color colorPage = ((press && hover) || select) ? m_FocusColor : (hover ? Color.FromArgb(100, m_FocusColor) : m_TitleColor);

            GraphicsHelper.FillBack(g, rect, colorPage, enable);
        }
        protected virtual void DrawRivetedTabPageText(Graphics g, bool enable, DTG group, DTGP page, Rectangle rectText)
        {
            var align = group.Alignment;
            //GraphicsHelper.FillBack(g, rectText, Color.FromArgb(100, Color.Cyan), enable);
            if (align == DA.Top) { GraphicsHelper.DrawString(g, page.Text, this.Font, this.ForeColor, rectText, this.Enabled); }
            else if (align == DA.Bottom) { GraphicsHelper.DrawString(g, page.Text, this.Font, this.ForeColor, rectText, this.Enabled); }
            else if (align == DA.Left) { GraphicsHelper.DrawString(g, page.Text, this.Font, this.ForeColor, rectText, this.Enabled, 90); /*270*/ } 
            else if (align == DA.Right) { GraphicsHelper.DrawString(g, page.Text, this.Font, this.ForeColor, rectText, this.Enabled, 90); }
        }
        protected virtual void DrawRivetedTabPageIcon(Graphics g, bool enable, DTG group, DTGP page, Rectangle rectIcon, Image icon)
        {
            if (!this.Enabled) icon = GraphicsHelper.CreateDisabledImage(icon);
            GraphicsHelper.DrawImage(g, icon, rectIcon);
        }



    }


    [ToolboxItem(false)]
    public class XIDEPanelCenter : System.Windows.Forms.UserControl
    {
        public XIDEPanelCenter(XIDEPanel idePanel)
        {
            base.BackColor = Color.Transparent;
            base.Dock = DockStyle.Fill;
            this.IDEPanel = idePanel;
            base.DoubleBuffered = true;
        }

        public XIDEPanel IDEPanel { get; private set; }

        public XIDETabGroup FindGroup()
        {
            var ctrls = this.Controls;
            if (ctrls.Count <= 0) return null;

            foreach (var ctrl in ctrls)
            {
                if (ctrl is XIDETabGroup) { return (XIDETabGroup)ctrl; }
                if (ctrl is XIDESplitControl)
                {
                    var splitCtrl = (XIDESplitControl)ctrl;
                    var group = splitCtrl.FindGroup();
                    if (group != null) return group;
                }
            }
            return null;
        }

        protected override void OnEnter(EventArgs e)
        {
            base.OnEnter(e);
            XIDEPopPanel.TogglePopGroup(null);
        }

        public void ResetLayout()
        {
            var ctrls = this.Controls;

            foreach (var ctrl in ctrls)
            {
                if (ctrl is XIDEPanelCenter) { ((XIDEPanelCenter)ctrl).ResetLayout(); }
                if (ctrl is XIDESplitControl) { ((XIDESplitControl)ctrl).ResetLayout(); }
            }

            this.DoLayout();
        }

        protected bool m_DoLayout = false;
        public void DoLayout()
        {
            //try
            //{
            //    m_DoLayout = true;
            //    if (this.Disposing || this.IsDisposed || this.IDEPanel == null) return;
            //    //Console.WriteLine("IDEPanelCenter.DoLayout() " + DateTime.Now.ToString("HH:mm:ss fff"));
            //    //好像没啥事要做的
            //}
            //finally { m_DoLayout = false; }
        }
    }


    public class XIDELayoutInfo
    {
        public XIDELayoutInfo(XIDELayoutEnum @enum, XIDETabGroup ctrl)
        {
            this.Enum = @enum;
            this.TabGroup = ctrl;
        }
        public XIDELayoutInfo(XIDELayoutEnum @enum, XIDEPanelCenter ctrl)
        {
            this.Enum = @enum;
            this.CenterPanel = ctrl;
        }
        public XIDELayoutInfo(XIDELayoutEnum @enum, XIDESplitControl ctrl)
        {
            this.Enum = @enum;
            this.SplitControl = ctrl;
        }

        public XIDELayoutEnum Enum { get; set; }
        public Rectangle Rect { get; set; }
        public XIDETabGroup TabGroup { get; set; }
        public XIDEPanelCenter CenterPanel { get; set; }
        public XIDESplitControl SplitControl { get; set; }
        public XIDELayoutInfo Layout1 { get; set; }
        public XIDELayoutInfo Layout2 { get; set; }
        public XIDETipGroupRect TipRect
        {
            get
            {
                const int SIZE = 112;
                Rectangle rect1 = this.Rect;
                Rectangle rect2 = new Rectangle(0, 0, SIZE, SIZE);
                if (rect1.Width < rect2.Width || rect1.Height < rect2.Height) return XIDETipGroupRect.Empty;
                Rectangle rect3 = new Rectangle((rect1.X) + (rect1.Width - rect2.Width) / 2, (rect1.Y) + (rect1.Height - rect2.Height) / 2, rect2.Width, rect2.Height);
                return new XIDETipGroupRect(rect3, !(TabGroup != null && TabGroup.State == DTGS.Expand));
            }
        }
        public XIDEPanel IDEPanel
        {
            get
            {
                if (TabGroup != null && TabGroup.IDEPanel != null) return TabGroup.IDEPanel;
                if (SplitControl != null && SplitControl.IDEPanel != null) return SplitControl.IDEPanel;
                return null;
            }
        }


        public bool MouseInRect()
        {
            var ctrl = (TabGroup as System.Windows.Forms.Control) ?? (CenterPanel as System.Windows.Forms.Control) ?? (SplitControl as System.Windows.Forms.Control);
            var point1 = System.Windows.Forms.Control.MousePosition;
            var point2 = ctrl.PointToClient(point1);
            return Rect.Contains(point2);
        }
        public XIDEAlignment MouseInTipRect()
        {
            var ctrl = (TabGroup as System.Windows.Forms.Control) ?? (CenterPanel as System.Windows.Forms.Control) ?? (SplitControl as System.Windows.Forms.Control);
            if (ctrl == null) return XIDEAlignment.None;
            var point1 = System.Windows.Forms.Control.MousePosition;
            var point2 = ctrl.PointToClient(point1);
            return TipRect.Contains(point2);
        }

        public List<XIDELayoutInfo> GetTabGroups()
        {
            if (this.Enum == XIDELayoutEnum.TabGroup) return new List<XIDELayoutInfo> { this };
            else if (this.Enum == XIDELayoutEnum.CenterPanel)
            {
                List<XIDELayoutInfo> list = new List<XIDELayoutInfo>();
                var result1 = Layout1 == null ? null : Layout1.GetTabGroups();
                if (result1 != null) list.AddRange(result1);
                return list;
            }
            else
            {
                List<XIDELayoutInfo> list = new List<XIDELayoutInfo>();

                var result1 = Layout1 == null ? null : Layout1.GetTabGroups();
                if (result1 != null) list.AddRange(result1);

                var result2 = Layout2 == null ? null : Layout2.GetTabGroups();
                if (result2 != null) list.AddRange(result2);

                return list;
            }
        }
    }

    public class XIDEAreaInfo
    {
        public XIDEAreaInfo(XIDEAlignment align, XIDEPanel ctrl)
        {
            this.Align = align;
            this.IDEPanel = ctrl;
        }

        public XIDEAlignment Align { get; set; }
        public XIDEPanel IDEPanel { get; set; }
        public Rectangle Rect { get; set; }
        public bool MouseInRect()
        {
            var ctrl = Align == DA.Center ? (this.IDEPanel.CenterPanel as System.Windows.Forms.Control) : (this.IDEPanel as System.Windows.Forms.Control);
            var point1 = System.Windows.Forms.Control.MousePosition;
            var point2 = ctrl.PointToClient(point1);
            return Rect.Contains(point2);
        }
        public XIDEAlignment MouseInTipRect()
        {
            if (MouseInRect()) return Align;
            return XIDEAlignment.None;
        }
    }


    public struct XIDETipGroupRect
    {
        public static readonly XIDETipGroupRect Empty = new XIDETipGroupRect();

        public XIDETipGroupRect(Rectangle rect, bool onlyCenter) : this()
        {
            int swidth = 32;
            int sheight = 32;
            int split = (rect.Width - (swidth * 3)) / 4;

            RectFull = rect;
            RectCenter = new Rectangle(RectFull.X + swidth + (split * 2), RectFull.Y + sheight + (split * 2), swidth, sheight);

            OnlyCenter = onlyCenter;
            if (onlyCenter)
            {
                RectTop = RectBottom = RectLeft = RectRight = Rectangle.Empty;
            }
            else
            {
                RectTop = new Rectangle(RectFull.X + swidth + (split * 2), RectFull.Y + split, swidth, sheight);
                RectBottom = new Rectangle(RectFull.X + swidth + (split * 2), RectFull.Y + (sheight * 2) + (split * 3), swidth, sheight);
                RectLeft = new Rectangle(RectFull.X + split, RectFull.Y + sheight + (split * 2), swidth, sheight);
                RectRight = new Rectangle(RectFull.X + (swidth * 2) + (split * 3), RectFull.Y + sheight + (split * 2), swidth, sheight);
            }
        }

        public bool OnlyCenter { get; set; }
        public Rectangle RectFull { get; set; }
        public Rectangle RectCenter { get; set; }
        public Rectangle RectTop { get; set; }
        public Rectangle RectBottom { get; set; }
        public Rectangle RectLeft { get; set; }
        public Rectangle RectRight { get; set; }

        public int Width { get { return RectFull.Width; } }
        public int Height { get { return RectFull.Height; } }

        public XIDEAlignment Contains(Point point)
        {
            if(RectCenter.Contains(point)) return XIDEAlignment.Center;
            if(RectTop.Contains(point)) return XIDEAlignment.Top;
            if(RectBottom.Contains(point)) return XIDEAlignment.Bottom;
            if(RectLeft.Contains(point)) return XIDEAlignment.Left;
            if(RectRight.Contains(point)) return XIDEAlignment.Right;
            return XIDEAlignment.None;
        }
    }


    public enum XIDELayoutEnum
    {
        CenterPanel,
        TabGroup,
        Vertical,
        Horizontal,
    }

    public enum XIDEAlignment
    {
        None,
        Top,
        Bottom,
        Left,
        Right,
        Center,
        FloatCenter,
    }

    public class XIDEEventArgs : EventArgs
    {
        public XIDETabGroup Control;
        public XIDEAreaInfo TipArea;
        public XIDELayoutInfo TipLayout;
        public XIDEAlignment Alignment;
    }

}
